﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Security;
using System.Web;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition;

namespace Steve.UI.Extensions
{
    [Export(typeof(IAccountService))]
    [Export(typeof(ISiteModuleExtension))]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public sealed class FormsAuthenticationMembershipAccountService : IAccountService, ISiteModuleExtension
    {
        [Import]
        public IConfiguration Config { get; set; }

        [Import]
        public IHttpContextBaseBuilder ContextBuilder { get; set; }

        public MembershipUser GetAuthenticatedUser()
        {
            return Membership.GetUser();
        }

        public MembershipUser GetUser()
        {
            var u = Membership.GetUser();

            if (u != null) return u;

            var cookieId = GetRequestCookieId(ContextBuilder.BuildCurrent(), Config.MembershipIdCookieName);

            if (cookieId == null) return null;

            return Membership.GetUser(cookieId.Value);
        }

        private static Guid? GetRequestCookieId(HttpContextBase ctx, string cookieName)
        {
            var reqCookie = ctx.Request.Cookies[cookieName];

            if (reqCookie != null && !string.IsNullOrWhiteSpace(reqCookie.Value))
            {
                try
                {
                    return new Guid(reqCookie.Value);
                }
                catch (FormatException)
                {
                    //ignore
                }
                catch (OverflowException)
                {
                    //ignore
                }
            }

            return null;
        }

        void ISiteModuleExtension.ProcessRewrite(HttpContextBase ctx, RewriteResult result)
        {
            //ignore
        }

        void ISiteModuleExtension.ProcessBeginRequest(HttpContextBase ctx, UrlObject url)
        {
            //ignore
        }

        void ISiteModuleExtension.ProcessPostAuthenticateRequest(HttpContextBase ctx)
        {
            if (ctx == null) throw new ArgumentNullException("ctx");

            //store current logged in membership id if its not stored or a different one is stored

            var cookieName = Config.MembershipIdCookieName;

            var cookieDomain = FormsAuthentication.CookieDomain;

            var u = Membership.GetUser();

            if (u != null)
            {
                var id = (Guid)u.ProviderUserKey;
                var cookieId = GetRequestCookieId(ctx, cookieName);

                if (cookieId == null || cookieId != id)
                {
                    var respCookie = new HttpCookie(cookieName, id.ToString("n"));
                    respCookie.HttpOnly = true;
                    respCookie.Domain = cookieDomain;
                    respCookie.Expires = DateTime.Now.AddYears(20);

                    ctx.Response.Cookies.Add(respCookie);
                }
            }
        }

        public bool ValidateUser(string userName, string password)
        {
            return Membership.ValidateUser(userName, password);
        }

        public void SignIn(string userName)
        {
            FormsAuthentication.SetAuthCookie(userName, false);
        }

        public void SignOut()
        {
            FormsAuthentication.SignOut();
        }

        public void ClearUser()
        {
            SignOut();

            var cookieName = Config.MembershipIdCookieName;

            var respCookie = new HttpCookie(cookieName);
            respCookie.Expires = DateTime.Now.AddDays(-1);

            ContextBuilder.BuildCurrent().Response.Cookies.Add(respCookie);
        }
    }
}
